#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>

#include "lockgroup.hpp"
#include "LOG.hpp"
#include <string.h>
#include <strings.h>
#include <error.h>
#include <unistd.h>
#include "InetAddr.h"
#include <functional>
using namespace std;

const static int defultsocketfd = -1;
using func_t = function<string(const string&)>;

enum
{
    SOCKET_ERROR = 0,
    BIND_ERROR,
    USEGE_ERROR,
    READ_ERROR
};
class SocketSever
{
public:
    SocketSever(string ip, uint16_t port,func_t func)
        : _socketfd(defultsocketfd), _ip(ip), _port(port),_func(func)
    {
    }

    void InitSever()
    {
        // 1.创建套接字
        _socketfd = socket(AF_INET, SOCK_DGRAM, 0);
        if (_socketfd < 0)
        {
            LOG(FATAL, "socketfd error: %s", strerror(errno));
            exit(SOCKET_ERROR);
        }
        LOG(INFO, "Init success,socketfd:%d", _socketfd);

        // 2.绑定(bind) socketfd和网络信息 (ip 和 port)
        // 2.0 先创建一个socket_addr_in
        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);                  // port经过网络传输给对方，需要字节序的转换:主机序列——>网络序列
        //local.sin_addr.s_addr = INADDR_ANY;//内部用任意ip绑定，客户只要发给这个端口号，就直接发给我
        local.sin_addr.s_addr = inet_addr(_ip.c_str()); //"192.168.3.1" 点分十进制的字符串——ip地址，要转成整数——>4字节
        int n = bind(_socketfd, (sockaddr *)&local, sizeof(local));
        if (n < 0)
        {
            LOG(FATAL, "bind error: %s", strerror(errno));
            exit(BIND_ERROR);
        }
        LOG(INFO, "bind success");
    }

    void start()
    {
        _isrunning = true;
        while (_isrunning)
        {
            //1.让sever接收消息
            char request[1024];
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            ssize_t n = recvfrom(_socketfd,request,sizeof(request),0,(struct sockaddr*)&peer,&len);
            if(n < 0)
            {
                LOG(ERROR,"recvfrom fail:%s",strerror(errno));
                exit(READ_ERROR);
            }
            request[n] = 0;
            InetAddr addr(peer);
            LOG(INFO,"[%s:%d] to me a message: %s",addr.Ip().c_str(),addr.Port(),request);

            //将请求回调出去，交给外部处理
            string response = _func(request);
            //2.让sever发回消息
            sendto(_socketfd,response.c_str(),response.size(),0,(struct sockaddr*)&peer,len);
        }
    }

    void stop()
    {
        _isrunning = false;
    }
    ~SocketSever()
    {
    }

private:
    int _socketfd;
    string _ip;
    uint16_t _port;
    bool _isrunning;

    //交给上层回调
    func_t _func;
};